package com.tchepannou.limbe.interceptor;

import com.tchepannou.limbe.Controller;
import com.tchepannou.limbe.Interceptor;
import com.tchepannou.limbe.annotation.Action;
import com.tchepannou.limbe.mail.MailController;
import com.tchepannou.limbe.model.Model;
import com.tchepannou.limbe.service.OptionService;
import com.tchepannou.limbe.web.ActionController;
import com.tchepannou.util.StringUtil;

import javax.servlet.http.Cookie;
import javax.servlet.http.HttpServletRequest;
import java.lang.reflect.Method;
import java.util.ArrayList;
import java.util.Collections;
import java.util.Enumeration;
import java.util.List;
import java.util.Map;
import java.util.logging.Level;
import java.util.logging.Logger;

/**
 * User: herve
 * Date: 14-06-04 1:44 AM
 */
public class DebugInterceptor implements Interceptor
{
    private static final Logger LOG = Logger.getLogger(DebugInterceptor.class.getName());

    @Override
    public int before(Controller controller)
    {
        if (isEnabled(controller))
        {
            /* Controller */
            StringBuilder sb = new StringBuilder();
            sb.append("Controller\n");
            sb.append("\tClass: ").append(controller.getClass().getName()).append('\n');
            Action action = controller.getClass().getAnnotation(Action.class);
            if (action != null)
            {
                Class model = action.model();
                if (model != null && !model.equals(Model.class))
                {
                    sb.append("\tModel: ").append(model.getName()).append('\n');
                }
            }

            if (controller instanceof ActionController)
            {
                ActionController ctl = (ActionController)controller;
                HttpServletRequest req = ctl.getRequest();

                /* url */
                sb.append(req.getMethod()).append(' ').append(req.getPathInfo());
                String qs = req.getQueryString();
                if (qs != null)
                {
                    sb.append('?').append(qs);
                }
                sb.append('\n');

                /* Parameters */
                if (!req.getParameterMap().isEmpty())
                {
                    sb.append("Request Parameters\n");
                    for (Object name : req.getParameterMap().keySet())
                    {
                        String[] value = req.getParameterValues(name.toString());
                        sb.append('\t').append(name).append(": ");
                        if (value.length == 1)
                        {
                            sb.append(value[0]);
                        }
                        else
                        {
                            sb.append(StringUtil.merge(value, ","));
                        }
                        sb.append('\n');
                    }
                }

                /* Headers */
                if (req.getHeaderNames().hasMoreElements())
                {
                    sb.append("Request Headers\n");
                    for (Enumeration names = req.getHeaderNames() ; names.hasMoreElements() ; )
                    {
                        Object name = names.nextElement();
                        String value = req.getHeader(name.toString());
                        sb.append('\t').append(name).append(": ").append(value).append('\n');
                    }
                }

                /* Attributes */
                if (req.getAttributeNames().hasMoreElements())
                {
                    sb.append("Request Attributes\n");
                    for (Enumeration names = req.getAttributeNames() ; names.hasMoreElements() ; )
                    {
                        Object name = names.nextElement();
                        Object value = req.getAttribute(name.toString());
                        sb.append('\t').append(name).append(": ").append(value).append('\n');
                    }
                }

                /* Cookies */
                sb.append("Cookies\n");
                if (req.getCookies() != null)
                {
                    for (Cookie cookie : req.getCookies())
                    {
                        Object name = cookie.getName();
                        String value = cookie.getValue();
                        sb.append('\t').append(name).append(": ").append(value).append('\n');
                    }
                }
            }
            LOG.info(sb.toString());
        }
        return Interceptor.CONTINUE;
    }

    @Override
    public void after(Controller controller)
    {

    }

    @Override
    public int before(Method method, Controller controller)
    {
        return 0;
    }

    @Override
    public void after(Method method, Controller controller, Throwable e)
    {
        if (isEnabled(controller))
        {
            StringBuilder sb = new StringBuilder ();
            Map<String, Object> view = null;
            if (controller instanceof ActionController){
                view = ((ActionController)controller).getViewVariables();
            }
            else if (controller instanceof MailController){
                view = ((MailController)controller).getViewVariables();
            }
            if (view != null){
                sb.append("\nView Variables\n");
                List<String> names = new ArrayList<String>(view.keySet());
                Collections.sort(names);
                for (String name : names){
                    Object value = view.get(name);
                    if (value != null){
                        String svalue = StringUtil.shortText(value.toString(), 1024, "...");
                        sb.append('\t').append(name)
                            .append(" : ").append(value.getClass().getName())
                            .append(" = ").append(svalue).append('\n')
                        ;
                    }
                }
            }

            LOG.info(sb.toString());
            if (e != null)
            {
                LOG.log(Level.SEVERE, "Exception", e);
            }
        }
    }

    public boolean isEnabled (Controller controller)
    {
        OptionService os = controller.getContext().findService(OptionService.class);
        return "1".equals(os.get("debug.enabled", null));
    }
}
